package copyengine.resource.loadqueue
{
	import copyengine.resource.CEResMangerNotification;
	import copyengine.resource.dto.ResLoadStateDTO;
	import copyengine.resource.file.ICEResFile;
	import copyengine.utils.debug.CELog;
	import copyengine.utils.tick.GlobalTick;

	import org.puremvc.as3.interfaces.IFacade;

	public final class CEResLoadQueue
	{
		/**
		 * define the load connect number that resLoadSystem is use.
		 * as i tested , flash can open 15 connect loader at one time , so use the loader speed to control how many gbps
		 * that current system can use.
		 *
		 * LOAD_SPEED_FULL         no limited , use in perloading
		 * LOAD_SPEED_HIGHT      use in lazyloader state , will have little rpc call ,most of the time is loading stuff
		 * LOAD_SPPED_MIDDLE    use in player already login to the scence and no rpc happen
		 * LOAD_SPPED_LOW         use in rpc happen , system will move the gbps for rpc.
		 */
		public static const LOAD_SPEED_FULL:int = int.MAX_VALUE;
		public static const LOAD_SPEED_HIGHT:int = 10;
		public static const LOAD_SPPED_MIDDLE:int = 5;
		public static const LOAD_SPPED_LOW:int = 1;

		/**
		 * hold all resFile in current load queue.
		 * WARNINIG::
		 * 			this only hold unload resFile , if the file already been load ,then will removed from loadQueue
		 * 			@see more at function checkLoadState();
		 */
		private var allLoadQueueFileVector:Vector.<ICEResFile>;

		/**
		 * hold an reference of current loading file , in case the file will not be gc during loading.
		 */
		private var currentLoadingFileVector:Vector.<ICEResFile>;

		/**
		 * define load speed.(how many loader will use)
		 */
		private var loadSpeed:int = LOAD_SPEED_FULL;

		/**
		 *记录当前已经Load完成的File的Weight
		 */
		private var totalLoadedFileWeight:Number = 0;

		private var maxLoadWeight:int;
		private var loadPercent:int;

		/**
		 *use to notification other system when load status change.
		 */
		private var facade:IFacade;

		/**
		 * call this function when finished load all files.
		 */
		private var loadComplateCallBack:Function;

		private var resLoadStateDTO:ResLoadStateDTO;

		/**
		 * when add a file to loadQueue , will not start check current load state immediately
		 * it will buffer for one tick , then check. in case during add file loop return loadComplate event.
		 */
		private var isDuringAddBuffer:Boolean = false;

		public function CEResLoadQueue(_facade:IFacade, _loadComplateCallBack:Function)
		{
			facade = _facade;
			loadComplateCallBack = _loadComplateCallBack;

			allLoadQueueFileVector = new Vector.<ICEResFile>();
			currentLoadingFileVector = new Vector.<ICEResFile>();
			resLoadStateDTO = new ResLoadStateDTO();
		}


		public function addResToLoadQueue(_resFile:ICEResFile):void
		{
			for (var i:int = 0; i < allLoadQueueFileVector.length; i++)
			{
				if (allLoadQueueFileVector[i] == _resFile)
				{
					allLoadQueueFileVector.splice(i, 1);
					maxLoadWeight -= _resFile.maxWeight;
					break;
				}
			}
			allLoadQueueFileVector.push(_resFile);
			maxLoadWeight += _resFile.maxWeight;
			if (isDuringAddBuffer == false)
			{
				isDuringAddBuffer = true;
				GlobalTick.instance.callLaterAfterTickCount(tryToLoadRemainFile);
			}
		}

		/**
		 * check for load state , if have rest loader then start load next file.
		 */
		private function tryToLoadRemainFile():void
		{
			isDuringAddBuffer = false;
			var count:int = Math.max(loadSpeed - currentLoadingFileVector.length, 0);
			for (var i:int = 0; i < count; i++)
			{
				var resFile:ICEResFile = allLoadQueueFileVector.pop()
				// if currant file == null means all File has been loaded
				if (resFile != null)
				{
					resFile.startLoadFile(onResourceFileLoaded, onResourceFileLoadProgress, onRescouceFileLoadError);
					currentLoadingFileVector.push(resFile);
				}
				else
				{
					return;
				}
			}
		}

		/**
		 *  will call when one resFile has been loaded
		 */
		private function onResourceFileLoaded(_resFile:ICEResFile):void
		{
			CELog.log("Succeed Load Res File : " + _resFile.fileName);
			totalLoadedFileWeight += _resFile.maxWeight;
			for (var i:int = 0; i < currentLoadingFileVector.length; i++)
			{
				if (currentLoadingFileVector[i] == _resFile)
				{
					currentLoadingFileVector.splice(i, 1);
					break;
				}
			}
			tryToLoadRemainFile();
			// if currentLoadingFileVector not contain file means load already finished 
			//WARNINIG:: 
			//		this function muse call  after tryToLoadRemainFile() function .beacuse that function will change the length
			if (currentLoadingFileVector.length == 0)
			{
				loadFinished();
			}
			else
			{
				onLoadWeightChange();
			}
		}

		private function onRescouceFileLoadError(_file:ICEResFile):void
		{
			CELog.err("Can't load file : " + _file.fileName);
			onResourceFileLoaded(_file);
		}

		/**
		 * @private
		 *
		 *  will call when one basicResourceFile has progress change.
		 */
		private function onResourceFileLoadProgress(_file:ICEResFile):void
		{
			onLoadWeightChange();
		}

		private function onLoadWeightChange():void
		{
			//==每次Progress改变的时候都要重新算一下当前Load的Weight
			//因为Event.Complate不会再文件Load完成后立刻调用
			var totalLoadWeight:Number = totalLoadedFileWeight;
			for each (var resFile:ICEResFile in currentLoadingFileVector)
			{
				totalLoadWeight += resFile.currentWeight;
			}

			var preLoadPercent:int = loadPercent;
			loadPercent = (totalLoadWeight * 100) / maxLoadWeight;
			if (preLoadPercent != loadPercent)
			{
				resLoadStateDTO.currentLoadPercent = loadPercent;
				resLoadStateDTO.preLoadPercent = preLoadPercent;
				resLoadStateDTO.maxLoadWeight = maxLoadWeight;
				resLoadStateDTO.currentLoadWeight = totalLoadWeight;

				facade.sendNotification(CEResMangerNotification.LOADQUEUE_LOADPERCENT_CHANGE, resLoadStateDTO);
			}
		}

		private function loadFinished():void
		{
			CELog.log("All file in current loadQueue has been loaded");
			GlobalTick.instance.removeTickNodeByFunction(tryToLoadRemainFile);
			allLoadQueueFileVector.length = 0;
			allLoadQueueFileVector = null;
			currentLoadingFileVector.length = 0;
			currentLoadingFileVector = null;
			loadComplateCallBack.apply();
			totalLoadedFileWeight = 0;
		}

	}
}
